﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Text;
using Newtonsoft.Json;
using System.IO;
using Newtonsoft.Json.Linq;

namespace Test_API
{
    class L2PWebClient : WebClient
    {
        protected override WebRequest GetWebRequest(Uri address)
        {
            HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
            request.KeepAlive = true;
            request.ProtocolVersion = HttpVersion.Version10;
            return request;
        }
    }

    /// <summary>
    /// Should follow this link: http://stackoverflow.com/questions/4015324/http-request-with-post
    /// </summary>
    class HTTP
    {
        public enum RequestType
        {
            GET, POST, UPLOAD
        }

        /// <summary>
        /// Execute an API call operation as specified with the parameters.
        /// </summary>
        /// <param name="which">Any of the available methods: GET or POST</param>
        /// <param name="rootPath">API base path</param>
        /// <param name="methodName">Desired method name for the requested operation</param>
        /// <param name="queryString">Parameters which should be passed in url</param>
        /// <param name="dataSet">Parameters which should be passeed as post body</param>
        /// <param name="entry">Logentry which will contain API call status and result</param>
        /// <returns></returns>
        public static bool execute(RequestType which, string rootPath, string methodName, string queryString, Dictionary<string, object> dataSet, ref LogEntry entry)
        {
            string result = String.Empty;
            long start = DateTime.Now.Ticks;

            try
            {
                entry.methodName = methodName;
                entry.inputs = queryString + JsonConvert.SerializeObject(dataSet);
                start = DateTime.Now.Ticks;

                if (which == RequestType.GET)
                {
                    entry.inputs = queryString;
                    result = HTTP.GET(rootPath, methodName, queryString);
                }
                else if (which == RequestType.UPLOAD)
                {
                    result = HTTP.POST(rootPath + methodName + "?" + queryString, dataSet.urlEncodeValues(), RequestType.UPLOAD);
                }
                else
                {
                    result = HTTP.POST(rootPath + methodName + "?" + queryString, dataSet.urlEncodeValues(), RequestType.POST);
                }

                API_VERDICT.checkStatusFieldOnly(result, ref entry);
                entry.receivedData = result;

                entry.elapsedTime = (DateTime.Now.Ticks - start) / TimeSpan.TicksPerMillisecond;

                return true;
            }
            catch (Exception e)
            {
                entry.elapsedTime = (DateTime.Now.Ticks - start) / TimeSpan.TicksPerMillisecond;
                entry.verdict = entry.expectedResult == false;
                entry.receivedData = (e is JsonException ? API_VERDICT.PARSING_FAILURE : String.Empty) + e.Message;
            }
            return false;
        }

        private static string GET(string rootPath, string methodName, string queryString)
        {
            string url = rootPath + methodName + "?" + queryString;
            using (var wb = new WebClient())
            {
                try
                {
                    var response = wb.DownloadString(url);
                    return response;
                }
                catch (WebException exception)
                {
                    string responseText = "/* HTTP ERROR */";

                    if (exception.Response != null)
                    {
                        var resp = new StreamReader(exception.Response.GetResponseStream()).ReadToEnd();
                        responseText += resp;
                    }
                    else
                    {
                        responseText += exception.Message;
                    }
                    throw new Exception(responseText);
                }
            }
        }
        /*
        private static string POST(string url, Dictionary<string, object> postData, RequestType typeOfOperation)
        {
            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
            request.Method = "POST";
            request.KeepAlive = true;
            request.ProtocolVersion = HttpVersion.Version10;
            string postDataAsString = JsonConvert.SerializeObject(postData);
            byte[] byteArray = Encoding.UTF8.GetBytes(postDataAsString);
            request.ContentType = "application/json";
            request.ContentLength = byteArray.Length;
            Stream dataStream = request.GetRequestStream();
            dataStream.Write(byteArray, 0, byteArray.Length);
            dataStream.Close();

            // Get the response.
            WebResponse response = request.GetResponse();
            Console.WriteLine(((HttpWebResponse)response).StatusDescription);
            dataStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            string responseFromServer = reader.ReadToEnd();
            
            for (int i = 0; i < response.Headers.Count; i++)
                Console.WriteLine(response.Headers.GetKey(i) + " -- " + response.Headers.Get(i).ToString());

            reader.Close();
            dataStream.Close();
            response.Close();

            return responseFromServer;
        }
        */

        //*
        private static string POST(string url, Dictionary<string, object> postData, RequestType typeOfOperation)
        {
            using (var wb = new L2PWebClient())
            {
                try
                {
                    wb.Headers.Add("Content-Type", "application/json");
                    string json = String.Empty;
                    if (typeOfOperation == RequestType.POST)
                    {
                        json = JsonConvert.SerializeObject(postData);
                    }
                    else
                    {
                        //json = "{'stream':'" + postData["stream"] + "'}";
                        json = JsonConvert.SerializeObject(postData);
                    }
                    var response = wb.UploadString(url, json);
                    return response;
                }
                catch (WebException exception)
                {
                    string responseText = "/* HTTP ERROR */" + exception.Status.ToString();

                    if (exception.Response != null)
                    {
                        var resp = new StreamReader(exception.Response.GetResponseStream()).ReadToEnd();
                        responseText = resp;
                    }
                    throw new Exception(responseText);
                }
            }
        }
        //*/
    }
}